/**
 * 基础模型类 - 封装通用数据库操作（MVC模型层核心）
 * @class Model
 * @example
 * const User = new Model('user');
 * const user = await User.where({ id: 1 }).find();
 */

class Model {
    #tableName;       // 表名（私有，防止外部修改）
    #pool;          // 数据库连接池
    #queryBuilder;   // 查询构造器（储存临时查询条件）
    #lastSql;        // 最近执行的SQL（调试用）
    #belongsToBuilders;
    relatedModel = [];// 联表实例
    withname = [];
    foreignKey = [];// 关联外键
    localKey = [];// 关联主键
    autoWriteTimestamp = false;// 自动添加时间戳
    createTime = 'create_time'; // 创建时间字段
    updateTime = 'update_time'; // 更新时间字段
    deleteTime = 'delete_time'; // 软删除时间字段
    append = [];    // 添加的字段
    hidden = [];    // 隐藏的字段

    /**
     * 构造函数 - 初始化模型
     * @param {string} tableName - 数据库表名（需符合 MySQL 表名规范）
     */
    constructor(tableName) {
        // 校验表名合法性（防止SQL注入）
        if (!/^[a-zA-Z0-9_]+$/.test(tableName)) {
            throw new Error(`非法表名: ${tableName} (仅允许字母、数字、下划线)`);
        }
        this.#tableName = tableName;
        this.#pool = require('./config/db');    // 从配置中获取连接池
        this.#resetQueryBuilder();  // 初始化查询构建器
        this.#resetBelongsToBuilders(); // 初始化联表
    }
    /** 重建查询构建器（避免状态污染） */
    #resetQueryBuilder() {
        this.#queryBuilder = {
            where: {},      // WHERE 条件（对象形式）
            join: [],       // JOIN 条件
            fields: ['*'],  // 查询字段
            order: [],      // 排序规则
            limit: null,    // 分页限制
            offset: null,   // 分页偏移
            group: [],      // 分组规则
            params: [],     // 参数数组（用于预编译）
            lastInsertId: 0, // 最后插入的ID 
        };


    }
    #resetBelongsToBuilders() {
        // this.#belongsToBuilders = {
        //     relatedModel: [],
        //     withname: [],
        //     foreignKey: [],
        //     localKey: [],
        // }
        this.#belongsToBuilders = [];
        this.append = [];    // 添加的字段
        this.hidden = [];    // 隐藏的字段
    }

    /**
     * 执行 SQL 查询 （核心方法）
     * @provate
     * @returns {Promise<Array>}    查询结果
     */
    async #execute() {
        console.log(this.#lastSql);
        // console.log(this.#queryBuilder);
        console.log(this.#queryBuilder.params);
        console.log(this.#belongsToBuilders)

        // return;
        try {
            const [results] = await this.#pool.execute(this.#lastSql, this.#queryBuilder.params);
            this.#resetQueryBuilder(); // 重置状态
            // console.log(results)
            this.#queryBuilder.lastInsertId = results.insertId ? results.insertId : 0;
            return results;
        } catch (error) {
            console.log(`[SQL 执行错误] 表名: ${this.#tableName}, SQL: ${this.#lastSql}, 参数:`, this.#queryBuilder.params);
            throw new Error(`数据库操作失败: ${error.message}`);
        }
    }

    /**
     * 设置 WHERE 条件（支持链式调用）
     * @param {Object} conditions - 条件对象（如 {id: 1, age: {gt : 18}}）
     * @returns {Model} 当前实例（链式调用）
     */
    where(conditions) {
        if (typeof conditions !== 'object' || conditions === null) return this;

        // 解析复杂条件（支持gt/lt/eq 等操作符）
        for (const [key, value] of Object.entries(conditions)) {
            if (typeof value === 'object' && !Array.isArray(value)) {
                // 处理{ field: {gt: 18} } 形式
                for (const [op, val] of Object.entries(value)) {
                    this.#queryBuilder.where[`${key} ${op}`] = val;
                    this.#queryBuilder.params.push(val);
                }
            } else {
                // 处理普通等式
                this.#queryBuilder.where[key] = value;
                this.#queryBuilder.params.push(value);
            }
        }
        return this;
    }

    /**
     * 插入单条数据（自动返回插入 ID）
     * @param {Object} data - 要插入的字段和值（如 { name: '张三', age: 20 }）
     * @returns {Promise<number>} 插入的 ID
     */
    async insert(data) {
        if (typeof data !== 'object' || Object.keys(data).length === 0) {
            throw new Error('插入数据不能为空');
        }

        if (this.autoWriteTimestamp) {
            data[this.createTime] = new Date().getTime();
        }
        // 构建 INSERT 语句
        const fields = Object.keys(data).join(', ');
        const placeholders = Object.keys(data).map(() => '?').join(', ');
        this.#lastSql = `INSERT INTO ${this.#tableName} (${fields}) VALUES (${placeholders})`;
        this.#queryBuilder.params = Object.values(data);

        // 执行并返回插入 ID
        await this.#execute();
        return this.getLastInsertId();
    }

    /**
     * 查询单条数据（自动应用 WHERE/ORDER/LIMIT 条件）
     * @returns {Promise<Object|null>} 单条记录或 null
     */
    async find() {
        this.#buildSelectQuery();
        const result = await this.#execute();
        return result?.length > 0 ? result[0] : null
    }

    /**
     * 查询多条数据（支持分页、排序、字段过滤）
     * @param {string[]} [fields=[]] - 要查询的字段（默认 *）
     * @returns {Promise<Array>} 记录数组
     */
    async select(fields = []) {
        if (fields.length > 0) this.#queryBuilder.fields = fields;
        this.#buildSelectQuery();

        let result = await this.#execute();

        // 处理关联查询（批量优化）
        if (this.#belongsToBuilders.length > 0) {
            result = await this.#processBelongsToRelations(result);
        }

        // 处理添加字段和隐藏字段
        result = result.map(item => this.#processResult(item));

        this.#resetBelongsToBuilders()
        return result;
    }

    /**
     * 统计记录数（自动应用 WHERE 条件）
     * @param {string} [field='*'] - 统计字段（默认 *） 
     * @returns {Promise<number>} 记录总数
     */
    async count(field = '*') {
        this.#lastSql = `SELECT COUNT(${field}) AS total FROM ${this.#tableName}`;

        // 添加 WHERE 条件
        if (Object.keys(this.#queryBuilder.where).length > 0) {
            const whereClause = Object.entries(this.#queryBuilder.where).map(([key, value]) => `${key} = ?`).join(' AND ');
            this.#lastSql += ` WHERE ${whereClause}`;
            this.#queryBuilder.params = Object = Object.value(this.#queryBuilder.where);
        }

        const [result] = await this.#execute();
        return result[0]?.total || 0;
    }

    /**
     * 更新数据（自动应用 WHERE 条件）
     * @param {Object} data - 要更新的字段和值
     * @returns {Promise<number>} 受影响的行数
     */
    async update(data) {
        if (typeof data !== 'object' || Object.keys(data).length === 0) {
            throw new Error('更新数据不能为空');
        }

        // 构建 UPDATE 语句
        const setClause = Object.keys(data).map(key => `${key} = ?`).join(', ');
        this.#lastSql = `UPDATE ${this.#tableName} SET ${setClause}`;

        // 合并更新参数和 WHERE 参数
        this.#queryBuilder.params = [...Object.values(data), ...this.#queryBuilder.params];

        // 添加 WHERE 条件（无 WHERE 条件时抛出错误）
        if (Object.keys(this.#queryBuilder.where).length === 0) {
            throw new Error('更新操作必须指定 WHERE 条件');
        }
        const whereClause = Object.entries(this.#queryBuilder.where)
            .map(([key]) => `${key} = ?`)    // 已通过 params 传递值
            .join(' AND ');
        this.#lastSql += ` WHERE ${whereClause}`;
        const result = await this.#execute();
        return result?.changedRows;
    }

    /**
     * 软删除（标记删除，更新 deleted_time 字段）
     * @param {Object} [conditions={}] - 删除条件（默认删除全部）
     * @returns {Promise<number>} 受影响的行数
     */
    async softDelete(conditions = {}) {
        // 自动添加delete_time 字段（需确保表有该字段）
        const data = { ...conditions, [this.delete_time]: new Date().getTime() };
        return await this.update(data);
    }

    /**
     * 物理删除（危险操作，谨慎使用）
     * @param {Object} [conditions={}] - 删除条件（默认删除全部）
     * @returns {Promise<number>} 受影响的行数
     */
    async forceDelete(conditions = {}) {
        this.where(conditions);
        this.#lastSql = `DELETE FROM ${this.#tableName}`;

        // 添加 WHERE 条件
        if (Object.keys(this.#queryBuilder.where).length > 0) {
            const whereClause = Object.entries(this.#queryBuilder.where)
                .map(([key]) => `${key} = ?`)
                .join(' AND ');
            this.#lastSql += ` WHERE ${whereClause}`;
            this.#queryBuilder.params = Object.values(this.#queryBuilder.where);
        } else {
            throw new Error('物理删除必须指定 WHERE 条件');
        }
        const result = await this.#execute();
        return result?.affectedRows;
    }

    /**
     * 排序（链式调用）
     * @param {string} field - 排序字段
     * @param {'ASC'|'DESC'} direction - 排序方向
     * @returns {Model} 当前实例
     */
    order(field, direction = 'ASC') {
        const validDirections = ['ASC', 'DESC'];
        if (!validDirections.includes(direction.toUpperCase())) {
            throw new Error(`非法排序方向: ${direction}, 仅支持 ASC/DESC`);
        }
        this.#queryBuilder.order.push(`${field} ${direction.toUpperCase()}`);
        return this;
    }

    /**
     * 分页（链式调用）
     * @param {number} page - 页码（从 1 开始）
     * @param {number} pageSize - 每页数量
     * @returns {Model} 当前实例
     */
    page(page, pageSize) {
        this.#queryBuilder.limit = pageSize;
        this.#queryBuilder.offset = (page - 1) * pageSize;
        return this;
    }

    /**
     * 关联查询（BELONGS_TO）
     * @param {Model} relatedModel - 关联模型实例
     * @param {string} foreignKey - 外键（当前表）
     * @param {string} localKey - 主键（关联表）
     * @param {string} [as=''] - 关联结果别名（可选）
     * @returns {Model} 当前实例（支持链式调用）
     */
    belongsTo(relatedModel, foreignKey, localKey, as = '') {
        this.#belongsToBuilders.push({
            model: new (require(relatedModel)),
            foreignKey,
            localKey,
            as: as || `${relatedModel.#tableName}`
        })
        return this;
    }
    /**
     * 联表查询（支持链式调用）
     * @param {Model} relatedModel  要关联的模型路径
     * @param {string} foreignKey   关联外键（当前表）
     * @param {string} localKey     关联主键（关联表）
     * @param {string} withname     容器
     * @returns {Model}             当前实例
     * 示例 with('./model/Rank','rankid','id','ranklist')
     */
    with(relatedModel, foreignKey, localKey, withname = 'join_tablename') {
        this.#belongsToBuilders.relatedModel.push(new (require(relatedModel)));
        this.#belongsToBuilders.foreignKey.push(foreignKey);
        this.#belongsToBuilders.localKey.push(localKey);
        this.#belongsToBuilders.withname.push(withname);
        return this;
    }



    /**
     * 获取最近执行的 SQL （调试用）
     * @returns {string} 最近的 SQL 语句
     */
    getLastSql() {
        return this.#lastSql;
    }

    /**
     * 获取最后插入的 ID（仅INSERT后有效）
     * @returns {number} 插入的 ID
     */
    getLastInsertId() {
        return this.#queryBuilder.lastInsertId || 0;
    }

    /**
     * 私有方法：构建 SELECT 查询语句
     */
    #buildSelectQuery() {
        // 构建字段列表
        const fields = this.#queryBuilder.fields.join(', ');

        // 构建基础SQL
        this.#lastSql = `SELECT ${fields} FROM ${this.#tableName}`;

        // 添加 JOIN 条件
        if (this.#queryBuilder.join.length > 0) {
            this.#lastSql += ` ${this.#queryBuilder.join.join(' ')}`
        }

        // 添加 WHERE 条件
        const whereClauses = [];
        for (const [key, value] of Object.entries(this.#queryBuilder.where)) {

            if(Array.isArray(value)){
                whereClauses.push(`${key} IN (${value.join(', ')})`);
                continue;
            }
            whereClauses.push(key.split(' ').length == 2 ? `${key} ?` : `${key} = ?`);
        }
        if (whereClauses.length > 0) {
            this.#lastSql += ` WHERE ${whereClauses.join(' AND')}`;
            this.#queryBuilder.params = [...this.#queryBuilder.params]; // 确保参数顺序正确
        }

        // 添加排序
        if (this.#queryBuilder.order.length > 0) {
            this.#lastSql += ` ORDER BY ${this.#queryBuilder.order.join(', ')}`;
        }

        // 添加分页
        if (this.#queryBuilder.limit !== null) {
            this.#lastSql += ` LIMIT ?`;
            this.#queryBuilder.params.push(this.#queryBuilder.limit);
        }
        if (this.#queryBuilder.offset !== null) {
            this.#lastSql += ` OFFSET ?`;
            this.#queryBuilder.params.push(this.#queryBuilder.offset);
        }
    }

    /**
    * 私有方法：处理单条结果的动态字段和隐藏字段
    * @param {Object} item - 原始记录
    * @returns {Object} 处理后的记录
    */
    #processResult(item) {
        // 动态添加字段（调用 getter）
        this.append.forEach(key => {
            const getterName = `get${key.split('_').map(v => v[0].toUpperCase() + v.slice(1)).join('')}Attr`;
            item[key] = typeof this[getterName] === 'function' ? this[getterName](item) : null;
        });

        // 隐藏字段
        this.hidden.forEach(key => delete item[key]);

        return item;
    }

    /**
     * 私有方法：批量处理关联查询（解决 N+1 问题）
     * @param {Array} mainResult - 主查询结果
     * @returns {Promise<Array>} 合并关联数据后的结果
     */
    async #processBelongsToRelations(mainResult) {
        if (this.#belongsToBuilders.length === 0) return mainResult;
        for (const relations of this.#belongsToBuilders) {
            // const relations = this.#belongsToBuilders;
            // 收集所有关联外键值
            const foreignKeyValues = mainResult.map(item => item[relations.foreignKey])
                .flat()
                .filter(Boolean);

            // 批量查询关联数据
            const fkValues = [...new Set(foreignKeyValues)]  // 去重
            if (fkValues.length === 0) continue;

            // 构建批量查询条件
            const batchWhere = { [relations.localKey]: fkValues };
            const batchResult = await relations.model.where(batchWhere).select();

            // 创建外键到关联数据的映射
            const fkMap = new Map(batchResult.map(item => [item[relations.localKey], item]));

            // 合并到主结果
            mainResult.forEach(item => {
                const fkValue = item[relations.foreignKey];
                if (fkValue !== undefined && fkValue !== null) {
                    item[relations.as] = fkMap.get(fkValue) || null;
                }
            })
        }
        return mainResult;
    }
}
module.exports = Model;